/* LEDC (LED Controller) fade example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"

#include "esp_log.h"
#include "esp_err.h"
#include "esp_mac.h"
#include "rotat_ec11_drv.h"
#include "my_key_drv.h"
// #include "mdf_err.h"
// #include "mdf_common.h"

static const char *TAG = "key";

#define BUTTON_KEY_NUM             (2)
#define BUTTON_GPIO_KEY0           GPIO_NUM_9
#define BUTTON_GPIO_KEY1           GPIO_NUM_7


#define MIN_SHORT_KEY_PRESS_CNT    (150/portTICK_PERIOD_MS)
#define MAX_SHORT_KEY_PRESS_CNT    (1000/portTICK_PERIOD_MS)
#define MAX_LONG_KEY_PRESS_CNT     (2000/portTICK_PERIOD_MS)
#define RTC_SLOW_MEM               ((uint32_t*) (0x50000000))       /*!< RTC slow memory, 8k size */


/**
 * @brief Key status
 */
typedef struct {
    gpio_num_t gpio_num;
    key_event_t status;
    bool push;
    bool release;
    int backup_tickcount;
} button_key_t;

// static const char *TAG                    = "button_driver";
static QueueHandle_t  g_event_queue         = NULL;
static button_key_t g_button_key[BUTTON_KEY_NUM] = {0x0};


/***************************************************/
key_event_t button_key_get_status(uint8_t key_index)
{
    key_event_t status = g_button_key[key_index].status;
    return status;
}

void button_key_reset_status()
{
    for (int i = 0; i < BUTTON_KEY_NUM; ++i) {
        if (g_button_key[i].status != KEY_LONG_PRESS) {
            g_button_key[i].status = KEY_NONE;
        }
    }
}

static void IRAM_ATTR key_gpio_isr_handler(void *arg)
{
    uint32_t key_index = (uint32_t) arg;
    xQueueSendFromISR(g_event_queue, &key_index, NULL);
}

static void send_key_msg(gpio_num_t key_num, key_event_t event)
{
    MAIN_MSG_t send_msg = {0};

    send_msg.type = KEY_TYPE;
    if(key_num == g_button_key[0].gpio_num){
        send_msg.data.key.id = ROTATION1_KEY;
    }
    else if(key_num == g_button_key[1].gpio_num){
        send_msg.data.key.id = ROTATION2_KEY;
    }
    else{
        ESP_LOGE(TAG, " key_not_match");
        return;
    }
    send_msg.data.key.event = event;
    xQueueSend(my_main_queue, (void*)&send_msg, (TickType_t)0);
}



static void button_get_value_task(void *arg)
{
    uint32_t key_index = 0;

    for (int i = 0; i < BUTTON_KEY_NUM; i++) {
        if (gpio_get_level(g_button_key[i].gpio_num)) {
            g_button_key[i].backup_tickcount = xTaskGetTickCount();
            g_button_key[i].push   = false;
            g_button_key[i].status = KEY_NONE;

        } else if (g_button_key[i].push) {
            g_button_key[i].status = KEY_SHORT_RELEASE;
            g_button_key[i].push   = false;
        }
    }

    for (;;) {
        key_index                = -1;
        button_key_t *button_key = NULL;

        if (!xQueueReceive(g_event_queue, &key_index, 1000/portTICK_PERIOD_MS)) {
            // printf("key_queue_timeout, rtc_time[%ld] \r\n", xTaskGetTickCount());
            for (int i = 0; i < BUTTON_KEY_NUM; i++) {
                button_key = g_button_key + i;
                uint8_t execution_time_ms = 10;
                uint32_t spent_timer_ms   = (xTaskGetTickCount() - button_key->backup_tickcount);
                // printf("spent_timer_ms:[%ld], push[%d], status[%d] \r\n", spent_timer_ms, button_key->push, button_key->status);
                if (spent_timer_ms > MAX_LONG_KEY_PRESS_CNT - execution_time_ms
                        && button_key->push == true) {
                    button_key->push = false;

                    if (key_index == -1) {
                        key_index = i;          //----------按键长按--按下
                        button_key->status = KEY_LONG_PRESS;
                        ESP_LOGI(TAG, "gpio_num[%d], long_press\r\n", button_key->gpio_num);
                        send_key_msg(button_key->gpio_num, KEY_LONG_PRESS);
                        // ESP_LOGI(TAG, "key_index: %d", key_index);
                    } else {
                        button_key->status = KEY_NONE;
                        // mdf_event_loop_send(MDF_EVENT_BUTTON_KEY_EXCEPTION, (void *)key_index);
                        // ESP_LOGI(TAG, "Exception, gpio_num: %d", button_key->gpio_num);
                        key_index = -1;
                        break;
                    }
                }
            }

            if (key_index != -1) {
                // mdf_event_loop_send(MDF_EVENT_BUTTON_KEY_LONG_PRESS_PUSH, (void *)key_index);
                // ESP_LOGI(TAG, "long_press_push, gpio_num: %d, status: %d", key_index, button_key->status);
            }

            continue;
        }

        // 队列收到按键信息后，才进入后面程序执行[中断方式是双边沿中断]
        button_key = g_button_key + key_index;
        int key_level = gpio_get_level(button_key->gpio_num);
        
        vTaskDelay(100/ portTICK_PERIOD_MS);
            // -------消抖 200ms
        if (key_level != gpio_get_level(button_key->gpio_num)) {
            button_key->backup_tickcount = 0;
            button_key->push    = false;
            button_key->release = false;
            continue;
        }

        if (key_level == 0) {
            if(false == button_key->push){  // 刚按下时，记录当前时间
                button_key->backup_tickcount = xTaskGetTickCount();
                // printf("get_time_cnt[%d]\r\n", button_key->backup_tickcount);
            }
            button_key->push = true;
            // mdf_event_loop_send(MDF_EVENT_BUTTON_KEY_PUSH, (void *)key_index);
            g_button_key[key_index].status = KEY_NONE;
        } else if (button_key->push) {
            button_key->release = true;
        }

        if (button_key->push && button_key->release) {
            int spent_timer_ms = (xTaskGetTickCount() - button_key->backup_tickcount);

            ESP_LOGI(TAG, "release get_time_cnt[%ld]\r\n", xTaskGetTickCount());
            button_key->push    = false;
            button_key->release = false;
            // 短按抬起
            if ((spent_timer_ms > MIN_SHORT_KEY_PRESS_CNT) && (spent_timer_ms < MAX_SHORT_KEY_PRESS_CNT)) {
                button_key->status = KEY_SHORT_RELEASE;
      
                ESP_LOGI(TAG," SHORT_release  \r\n");

                send_key_msg(button_key->gpio_num, KEY_SHORT_RELEASE);
            } 
            ESP_LOGI(TAG, "release, gpio_num: %d, time:[%ld]ms\r\n", button_key->gpio_num, spent_timer_ms * portTICK_PERIOD_MS);

        }
            // 长按 抬起
        if((button_key->status == KEY_LONG_PRESS))
        {
            button_key->status = KEY_LONG_RELEASE;
            ESP_LOGI(TAG, "LONG_PRESS_RELEASE \r\n");
            send_key_msg(button_key->gpio_num, KEY_LONG_RELEASE);
        }
    }
    vTaskDelete(NULL);
}

esp_err_t button_driver_init()
{
    esp_err_t ret = ESP_OK;
    
    memcpy(g_button_key, RTC_SLOW_MEM, sizeof(button_key_t) * BUTTON_KEY_NUM);

    if (g_button_key[0].gpio_num != BUTTON_GPIO_KEY0) {
        memset(g_button_key, 0, sizeof(button_key_t) * BUTTON_KEY_NUM);
        g_button_key[0].gpio_num = BUTTON_GPIO_KEY0;
        g_button_key[1].gpio_num = BUTTON_GPIO_KEY1;
    }

    gpio_config_t key_config = {
        .intr_type    = GPIO_INTR_ANYEDGE,
        .pin_bit_mask = BIT64(g_button_key[0].gpio_num) | BIT64(g_button_key[1].gpio_num),
        .mode         = GPIO_MODE_INPUT,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en   = GPIO_PULLUP_ENABLE,
    };

    ret = gpio_config(&key_config);
    if(ESP_OK != ret){
        printf("key_gpio cfg :err");
    }

    /**< Create a queue to handle gpio event from isr */
    g_event_queue = xQueueCreate(6, sizeof(uint32_t));

    /**< Install gpio isr service */
    gpio_install_isr_service(false);

    /**< Hook isr handler for specific gpio pin */
    for (int i = 0; i < BUTTON_KEY_NUM; ++i) {
        gpio_isr_handler_add(g_button_key[i].gpio_num, key_gpio_isr_handler, (void *)i);

    }

    ret = xTaskCreate(button_get_value_task, "button_get_value", 4096, NULL, 15, NULL);
    if(ret == 0){
        ESP_LOGE(TAG, "creat button_get_value_task err!!");
		return ret;
    }
   
    ESP_LOGI(TAG, "key_init succ \r\n");
    return ret;
}

esp_err_t button_driver_deinit()
{
    // ESP_LOGI(TAG, "Power down");
    // gpio_set_level(BUTTON_GPIO_POWER_SWITCH, false); ESP_LOGI(TAG, "recv_msg_index[%d] \r\n", (led_pwm_index_e)element_message.index);

    return ESP_OK;
}
